Skip to content

refactor(layers): flip the output seam — view bridge moves into features/feed (#493 PR-3) - #503

Merged
Juliusolsson05 merged 2 commits into
mainfrom
refactor/flip-view-seam
Jul 9, 2026
Merged

Juliusolsson05 merged 2 commits into
mainfrom
refactor/flip-view-seam

Conversation

@Juliusolsson05

Copy link
Copy Markdown
Owner

Part 3 of 3 for #493, stacked on #502 (which stacks on #501). Plan: docs/superpowers/plans/2026-07-09-layer-isolation.md §4.

What

rendering/view/ dissolves. ledgerFeedItems.ts (the RenderLedger → FeedRenderItem[] bridge) + useLedgerFeedItems.ts (the producer hook) move to features/feed/ledger/. Every formerly-inverted import becomes legal: FeedRenderItem/VisibleDecision/groupSemanticActivity are now same-layer siblings, and RenderLedger/RenderRow flow feed → rendering, the sanctioned direction. The react import leaves rendering/ entirely — the decide layer is now framework-free.

groupSemanticActivity stays feed-side (plan D3): issue PR-2's "move it into rendering/view" and PR-3's "move the view into feed" contradicted each other; the end state wins — presentation grouping is render-layer.

Replay un-inverted by injection. The harness (recordedSession.ts) now stops at RenderLedger — the decide layer's own output — and takes an injected projectItems: ReplayItemsProjection for the feed-item stage. The three replay/corpus tests inject the REAL production bridge from features/feed/ledger, so full-stack coverage (including the #239 dropped-candidate accounting) is byte-for-byte what it was; test files are outside the layer contract by design.

Issue #493 acceptance (verified one-off, per the issue's own "grep, not a CI lock")

$ grep -rn "@renderer/features\|@renderer/workspace\|from 'react'" src/renderer/src/rendering/ --include='*.ts' | grep -v '\.test\.'
(empty)
$ grep -rn "@renderer/\(workspace\|features\|app-state\)\|from 'react'" src/renderer/src/session-runtime/
(empty)

Three folders, one-directional: session-runtime/ (ingest) ← rendering/ (decide) ← features/feed/ (render). The ledger consumes exactly RuntimeRenderInput, emits exactly RenderLedger/RenderRow[], and the bridge to FeedRenderItem is feed-owned.

Gates

tsc node+web clean · vitest 467/467 · remote-client build OK · stack is linear on origin/main (merge is a fast-forward, so the per-PR gates ARE the merge-simulation).

After the stack merges: close #493 quoting the greps; small follow-up refreshes docs/rendering/rendering-system.md's where-to-look index for the new paths.

🤖 Generated with Claude Code

…res/feed (#493 PR-3)

rendering/view/ ceases to exist:
- ledgerFeedItems.ts (+ test) and useLedgerFeedItems.ts move to
  features/feed/ledger/. Every one of the bridge's imports is now legal:
  FeedRenderItem / VisibleDecision / groupSemanticActivity are same-layer
  siblings; RenderLedger/RenderRow come from rendering/model (feed ->
  rendering, the sanctioned direction). The react import leaves rendering/
  entirely — the decide layer is now framework-free.
- groupSemanticActivity STAYS feed-side (plan D3): issue PR-2 wanted it in
  rendering/view, but with the whole view stage relocating here that would
  have been round-trip churn; presentation grouping is render-layer.

Replay harness un-inverted by injection:
- recordedSession.ts no longer imports the bridge. New seam:
  ReplayOptions.projectItems (ReplayItemsProjection) — the harness runs
  slices -> adapter -> ledger and stops at RenderLedger, the decide
  layer's own output; projecting rows into feed items is the render
  layer's job, injected by callers. ReplayTick.feedItems is unknown[]
  (empty when no projector given).
- recordedSession.test / invariants.test / recordingCorpus.test inject the
  REAL production bridge from features/feed/ledger, so full-stack coverage
  (incl. the #239 dropped-candidate accounting) is unchanged — test files
  are outside the layer contract by design.

The #493 acceptance now holds and is grep-verified:
  grep -rn "@renderer/features|@renderer/workspace|from 'react'" \
    src/renderer/src/rendering/ --include='*.ts' | grep -v '\.test\.'  # -> empty
  grep -rn "@renderer/(workspace|features|app-state)|from 'react'" \
    src/renderer/src/session-runtime/                                  # -> empty

Three folders, one-way: session-runtime (ingest) <- rendering (decide) <-
features/feed (render); the ledger consumes exactly RuntimeRenderInput and
emits exactly RenderLedger/RenderRow[].

Gates: tsc node+web clean, vitest 467/467, remote-client build OK. Stack
is linear on origin/main (fast-forward merge).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rojection, refresh moved-path comments

Two Claude + two Codex reviewers over the full stack; zero blockers. The
two actionable findings:

- projectItems is now a REQUIRED ReplayOptions field (codex finding): an
  omitted projection was indistinguishable from "projected with zero
  drops", silently vacating the #239 dropped-candidate invariant for that
  run. Required-field = the forgotten-injection mistake is a compile
  error, not a green-but-hollow test.
- Stale comment path pointers to pre-#493 module locations refreshed
  (claude finding): reconstructSlices mirror-source block, Feed.tsx ghost
  notes, streamingWriteInput, observations/{ghosts,semantic},
  providerConfig, main/{ghostJournal,index}. Navigation pointers are
  exactly what the CLAUDE.md comment policy exists to keep accurate.

Codex's remaining finding — the phone's hard-coded lastJsonlEntryAt: 0 —
pre-exists this stack (the old cast hid the same value) and needs real
committed-tail plumbing on the wire protocol; deferred to a follow-up
rather than smuggled into a behavior-preserving refactor.

Gates: tsc node+web clean, vitest 467/467.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Base automatically changed from refactor/render-input-contract to main July 9, 2026 08:24
@Juliusolsson05
Juliusolsson05 changed the base branch from refactor/render-input-contract to main July 9, 2026 08:24
@Juliusolsson05
Juliusolsson05 merged commit cfe35ee into main Jul 9, 2026
@Juliusolsson05
Juliusolsson05 deleted the refactor/flip-view-seam branch July 9, 2026 08:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

App-wide layer isolation: ingest → decide → render as one-directional, grep-able folders

1 participant